package utils

import (
	"github.com/casbin/casbin/v2"
	mongodbadapter "github.com/casbin/mongodb-adapter/v3"
)

type CasbinManager struct {
	cas *casbin.Enforcer
}

var casbinManager *CasbinManager

func CasbinInst() *CasbinManager {
	if nil != casbinManager {
		return casbinManager
	}
	casbinManager = &CasbinManager{}
	return casbinManager
}

func (c *CasbinManager) Init(confPath string, url string) error {
	a, err := mongodbadapter.NewAdapter(url) // Your MongoDB URL.
	if err != nil {
		return err
	}
	e, err := casbin.NewEnforcer(confPath, a)
	if err != nil {
		return err
	}
	e.LoadPolicy()
	c.cas = e
	c.EnableAutoSave(true)
	c.ClearPolicy()
	c.SavePolicy()

	return nil
}

func (c *CasbinManager) Inited() bool {
	return c.cas != nil
}

func (c *CasbinManager) Enforce(data ...interface{}) (bool, error) {
	return c.cas.Enforce(data...)
}

func (c *CasbinManager) GetPolicy() [][]string {
	return c.cas.GetPolicy()
}

func (c *CasbinManager) LoadPolicy() error {
	return c.cas.LoadPolicy()
}

func (c *CasbinManager) LoadFilteredPolicy(data interface{}) error {
	return c.cas.LoadFilteredPolicy(data)
}

func (c *CasbinManager) AddPolicy(v1, v2, v3 string) (bool, error) {
	return c.cas.AddPolicy(v1, v2, v3)
}

func (c *CasbinManager) AddPolicies(data [][]string) (bool, error) {
	return c.cas.AddPolicies(data)
}

func (c *CasbinManager) RemovePolicy(v1, v2, v3 string) (bool, error) {
	return c.cas.RemovePolicy(v1, v2, v3)
}

func (c *CasbinManager) GetFilteredPolicy(idx int, data ...string) [][]string {
	return c.cas.GetFilteredPolicy(idx, data...)
}

func (c *CasbinManager) RemovePolices(data [][]string) (bool, error) {
	return c.cas.RemovePolicies(data)
}

func (c *CasbinManager) RemoveFilteredPolicy(fieldIndex int, fieldValues ...string) (bool, error) {
	return c.cas.RemoveFilteredPolicy(fieldIndex, fieldValues...)
}

func (c *CasbinManager) ClearPolicy() {
	c.cas.ClearPolicy()
}
func (c *CasbinManager) SavePolicy() {
	c.cas.SavePolicy()
}
func (c *CasbinManager) EnableAutoSave(b bool) {
	c.cas.EnableAutoSave(b)
}

func (c *CasbinManager) AddFunction(name string, f func(args ...interface{}) (interface{}, error)) {
	c.cas.AddFunction(name, f)
}

// AddFunction用法：
// func KeyMatch(key1 string, key2 string) bool {
// 	i := strings.Index(key2, "*")
// 	if i == -1 {
// 		return key1 == key2
// 	}
// 	if len(key1) > i {
// 		return key1[:i] == key2[:i]
// 	}
// 	return key1 == key2[:i]
// }

// func KeyMatchFunc(args ...interface{}) (interface{}, error) {
// 	name1 := args[0].(string)
// 	name2 := args[1].(string)
// 	return (bool)(KeyMatch(name1, name2)), nil
// }

// manager.AddFunction("my_func", KeyMatchFunc)

// model使用示例：
// [matchers]
// m = r.sub == p.sub && my_func(r.obj, p.obj) && r.act == p.act
